package cn.xuyun.cc.tcp.coder;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Logger;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;
import org.jboss.netty.handler.codec.frame.Delimiters;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;

import cn.xuyun.cc.tcp.TcpServerHandler;
import cn.xuyun.cc.tcp.TelnetServerHandler;
import cn.xuyun.cc.tcp.util.LogUtil;
import cn.xuyun.cc.tcp.vo.Constants;
import cn.xuyun.cc.tcp.vo.Entity;

public class MyDecoder extends FrameDecoder {

	private static Logger logger=Logger.getLogger(MyDecoder.class);
	
	
	
	@Override
	public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {

		InetSocketAddress address=(InetSocketAddress)ctx.getChannel().getLocalAddress();
		if(address.getPort()==4001)
		{
			logger.info("port 4001,console connected!");
			
			
			// 控制台发送命令
			 ChannelPipeline p = ctx.getPipeline();
			 
			 
			 p.addLast("framer", new DelimiterBasedFrameDecoder(
		                8192, Delimiters.lineDelimiter()));
		     p.addLast("decoder", new StringDecoder());
		     p.addLast("encoder", new StringEncoder());

		        // and then business logic.
		     p.addLast("handler", new TelnetServerHandler());
		     
		     p.remove(this);
			
			 // Send greeting for a new connection.
	        e.getChannel().write(
	                "Welcome to " + InetAddress.getLocalHost().getHostName() + "!\r\n");
	        e.getChannel().write("It is " + new Date() + " now.\r\n");
		}else{
			logger.info("port 4000,client connected!");
			ChannelPipeline p = ctx.getPipeline();
			p.addLast("encoder", new MyEncoder());
			p.addLast("handler", new TcpServerHandler());
		}
	}
	
	@Override
	public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		// TODO Auto-generated method stub
		
		InetSocketAddress address=(InetSocketAddress)ctx.getChannel().getLocalAddress();
		if(address.getPort()==4000)
		{
			TcpServerHandler.channel_device.remove(e.getChannel().getId());
			logger.info("channel size:"+TcpServerHandler.channel_device.size());
		}
		super.channelDisconnected(ctx, e);
	}
	
	@Override
	public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
	
		if (e instanceof ChannelStateEvent) {
			logger.info(e.toString());
		}
		super.handleUpstream(ctx, e);
	}
	
	@Override
	protected Object decode(ChannelHandlerContext context, Channel channel, ChannelBuffer buffer) throws Exception {
		
		if(buffer.readableBytes()<16){
			return null;
		}
		buffer.markReaderIndex();
		
		long magic=buffer.readLong();
		if(magic!=Constants.magic)
		{
			 throw new IllegalArgumentException("magic invalid");
		}
		
		
		int version=buffer.readInt();
		
		int data_len=buffer.readInt();
		
		if(data_len>buffer.readableBytes())// wait next read
		{
			buffer.resetReaderIndex();
			return null;
		}
		
		int send_time=buffer.readInt();
		
		int serial=buffer.readInt();
		
		int type=buffer.readInt();
		
		int cmd=buffer.readInt();
		
		int content_len=buffer.readInt();
		
		if(content_len>buffer.readableBytes())
		{
			throw new IllegalArgumentException("content_len invalid");
		}
		byte[] content=new byte[]{0};
		if(content_len>0)
		{
			content=buffer.readBytes(content_len).array();
		}
		
		int extra = buffer.readInt();
		
		Entity entity = new Entity();
		
		entity.setMagic(magic);
		entity.setVersion(version);
		entity.setData_len(data_len);
		entity.setSend_time(send_time);
		entity.setSerial(serial);
		entity.setType(type);
		entity.setCmd(cmd);
		entity.setContent_len(content_len);
		entity.setContent(content);
		entity.setExtra(extra);
		
		logger.info("receive from client");
		LogUtil.log(logger, entity);
		return entity;
	}
}
